package com.pf.utils;

import com.pf.dto.MailReq;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.InputStreamSource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;
import java.util.List;
import java.util.Map;

/**
 * 邮件工具类
 *
 * @author PF
 * @date 2021/6/24 20:35
 * @Version 1.0
 */
@Component
@Slf4j
public class MailUtils {

    static {
        /**
         * 邮件附件文件名长度如果大于60并且splitLongParameters的值为true，encodeParameters的值为true，文件名就会被截取。
         * 因此可设置该值为false，这样邮件附件名称就不会被截取
         */
        System.setProperty("mail.mime.splitlongparameters", "false");
    }

    /**
     * 邮件发送人
     */
    @Value("${spring.mail.username}")
    private String sender;


    @Autowired
    private JavaMailSender javaMailSender;
    /**
     * 使用freemarker模板发送邮件
     */
    @Autowired
    private FreeMarkerConfigurer freeMarkerConfigurer;

    /**
     * 使用thymeleaf模板发送邮件
     */
    @Autowired
    private TemplateEngine templateEngine;

    /**
     * 发送一个简单的文本邮件
     *
     * @param toUsers 接收人，可接收多个人
     * @param ccUsers 抄送人，可接收多个人
     * @param subject 邮件标题
     * @param content 邮件内容
     */
    public void sendTextMail(List<String> toUsers, List<String> ccUsers, String subject, String content) {
        if (sender == null || toUsers == null || subject == null || content == null) {
            log.error("MailUtils sendTextMail param error!");
            return;
        }
        SimpleMailMessage message = new SimpleMailMessage();
        // 发送人
        message.setFrom(sender);
        // 接收人
        message.setTo(toUsers.toArray(new String[toUsers.size()]));
        // 抄送人
        if (ccUsers != null) {
            message.setCc(ccUsers.toArray(new String[ccUsers.size()]));
        }
        // 邮件的主题
        message.setSubject(subject);
        // 邮件的内容信息
        message.setText(content);
        // 发送邮件
        javaMailSender.send(message);
        log.info("文本邮件已经发送...");
    }

    /**
     * 发送HTML内容邮件
     *
     * @param toUsers 接收人
     * @param ccUsers 抄送人
     * @param subject 邮件标题
     * @param content 邮件内容
     */
    public void sendHTMLMail(List<String> toUsers, List<String> ccUsers, String subject, String content) {
        if (sender == null || toUsers == null || subject == null || content == null) {
            log.error("MailUtils sendTextMail param error!");
            return;
        }
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage);

        try {
            // 发送人
            messageHelper.setFrom(sender);
            // 接收人
            messageHelper.setTo(toUsers.toArray(new String[toUsers.size()]));
            // 抄送人
            if (ccUsers != null) {
                messageHelper.setCc(ccUsers.toArray(new String[ccUsers.size()]));
            }
            // 邮件标题
            messageHelper.setSubject(subject);
            // 邮件内容（html），true表示默认内容类型为 text/html
            // 如果邮件内容为null，发送邮件时会报错 Exception writing Multipart。因此如果内容为空，则设置为""
            messageHelper.setText(StringUtils.isNotBlank(content) ? content : "", true);
            // 发送邮件
            javaMailSender.send(mimeMessage);
            log.info("带有html内容的邮件已经发送...");
        } catch (MessagingException e) {
            log.error("MailUtils sendHTMLMail error", e);
            throw new RuntimeException("邮件发送失败！");
        }
    }


    /**
     * 发送嵌入静态资源的邮件
     *
     * @param toUsers   接收人
     * @param ccUsers   抄送人
     * @param subject   邮件主题
     * @param contentId 内容id
     * @param content   邮件内容
     * @param filePath  内嵌图片路径
     */
    public void sendInlineResourceMail(List<String> toUsers, List<String> ccUsers, String subject, String contentId, String content, String filePath) {
        if (sender == null || toUsers == null || subject == null || content == null) {
            log.error("MailUtils sendInlineResourceMail param error!");
            return;
        }
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        try {
            MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true);
            // 发送人
            messageHelper.setFrom(sender);
            // 接收人
            messageHelper.setTo(toUsers.toArray(new String[toUsers.size()]));
            // 抄送人
            if (ccUsers != null) {
                messageHelper.setCc(ccUsers.toArray(new String[ccUsers.size()]));
            }
            // 邮件标题
            messageHelper.setSubject(subject);
            // 邮件内容（html），true表示默认内容类型为 text/html
            // 如果邮件内容为null，发送邮件时会报错 Exception writing Multipart。因此如果内容为空，则设置为""
            messageHelper.setText(StringUtils.isNotBlank(content) ? content : "", true);
            // 正文内嵌图片信息
            FileSystemResource resource = new FileSystemResource(new File(filePath));
            messageHelper.addInline(contentId, resource);

            // 发送邮件
            javaMailSender.send(mimeMessage);

            log.info("嵌入静态资源的邮件已经发送...");
        } catch (MessagingException e) {
            log.error("MailUtils sendInlineResourceMail error", e);
            throw new RuntimeException("邮件发送失败！");
        }
    }

    /**
     * 发送带有附件的邮件
     *
     * @param toUsers  接收人
     * @param ccUsers  抄送人
     * @param subject  邮件标题
     * @param content  邮件内容
     * @param filePath 附件路径（其实可以直接 InputStreamSource 做附加类型，因为 ClassPathResource resource = new ClassPathResource("/static/a.jpg") 返回的类型刚好适用）
     */
    public void sendAttachmentsMail(List<String> toUsers, List<String> ccUsers, String subject, String content, String filePath) {
        if (sender == null || toUsers == null || subject == null || content == null) {
            log.error("MailUtils sendAttachmentsMail param error!");
            return;
        }
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        try {
            MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true);
            // 发送人
            messageHelper.setFrom(sender);
            // 接收人
            messageHelper.setTo(toUsers.toArray(new String[toUsers.size()]));
            // 抄送人
            if (ccUsers != null) {
                messageHelper.setCc(ccUsers.toArray(new String[ccUsers.size()]));
            }
            // 邮件标题
            messageHelper.setSubject(subject);
            // 邮件内容（html），true表示默认内容类型为 text/html
            // 如果邮件内容为null，发送邮件时会报错 Exception writing Multipart。因此如果内容为空，则设置为""
            messageHelper.setText(StringUtils.isNotBlank(content) ? content : "", true);
            // 附件信息
            FileSystemResource resource = new FileSystemResource(new File(filePath));
            String fileName = filePath.substring(filePath.lastIndexOf(File.separator));
            messageHelper.addAttachment(fileName, resource);
            // 发送邮件
            javaMailSender.send(mimeMessage);
            log.info("带有附件的邮件已经发送...");
        } catch (MessagingException e) {
            log.error("MailUtils sendAttachmentsMail error", e);
            throw new RuntimeException("邮件发送失败！");
        }
    }


    /**
     * 推荐使用：内容为html或文本，支持多附件
     *
     * @param mailReq
     */
    public void sendHtmlAndAttachmentsMail(MailReq mailReq) {
        if (sender == null || mailReq == null || mailReq.getToUsers() == null || mailReq.getSubject() == null) {
            log.error("MailUtils sendHtmlAndAttachmentsMail param error!");
            return;
        }
        List<String> toUsers = mailReq.getToUsers();
        List<String> ccUsers = mailReq.getCcUsers();
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        try {
            MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true);
            // 发送人
            messageHelper.setFrom(sender);
            // 接收人
            messageHelper.setTo(toUsers.toArray(new String[toUsers.size()]));
            // 邮件标题
            messageHelper.setSubject(mailReq.getSubject());
            // 抄送人
            if (ccUsers != null) {
                messageHelper.setCc(ccUsers.toArray(new String[ccUsers.size()]));
            }
            // 邮件内容（html），true表示默认内容类型为 text/html
            // 如果邮件内容为null，发送邮件时会报错 Exception writing Multipart。因此如果内容为空，则设置为""
            messageHelper.setText(StringUtils.isNotBlank(mailReq.getContent()) ? mailReq.getContent() : "", true);
            // 附件信息
            List<MailReq.Attachment> attachments = mailReq.getAttachments();
            if (attachments != null) {
                for (MailReq.Attachment attachment : attachments) {
                    InputStreamSource inputStreamSource = new ByteArrayResource(attachment.getAttachmentBytes());
                    messageHelper.addAttachment(attachment.getAttachmentName(), inputStreamSource);
                }
            }

            // 发送邮件
            javaMailSender.send(mimeMessage);
            log.info("封装的html内容及附件邮件发送成功...");
        } catch (Exception e) {
            log.error("MailUtils sendHtmlAndAttachmentsMail error", e);
            throw new RuntimeException("邮件发送失败！");
        }
    }


    /**
     * 发送freemarker模板邮件
     *
     * @param toUsers        接收人
     * @param ccUsers        抄送人
     * @param subject        邮件标题
     * @param data           freemarker模板数据参数
     * @param freemarkerName freemarker模板名称
     */
    public void sendTemplateFreemarker(List<String> toUsers, List<String> ccUsers, String subject, Map<String, Object> data, String freemarkerName) {
        if (sender == null || toUsers == null || subject == null) {
            log.error("MailUtils sendTemplateFreemarker param error!");
            return;
        }
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        try {
            MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true);
            // 发送人
            messageHelper.setFrom(sender);
            // 接收人
            messageHelper.setTo(toUsers.toArray(new String[toUsers.size()]));
            // 抄送人
            if (ccUsers != null) {
                messageHelper.setCc(ccUsers.toArray(new String[ccUsers.size()]));
            }
            // 邮件标题
            messageHelper.setSubject(subject);
            // 获取freeMarker模板，填充数据
            Template template = freeMarkerConfigurer.getConfiguration().getTemplate(freemarkerName);
            String html = FreeMarkerTemplateUtils.processTemplateIntoString(template, data);
            messageHelper.setText(html, true);

            // 发送邮件
            javaMailSender.send(mimeMessage);
            log.info("freemarker模板邮件发送成功...");
        } catch (Exception e) {
            log.error("MailUtils sendTemplateFreemarker error", e);
            throw new RuntimeException("邮件发送失败！");
        }
    }

    /**
     * 发送thymeleaf模板邮件
     *
     * @param toUsers      接收人
     * @param ccUsers      抄送人
     * @param subject      邮件主体
     * @param data         模板数据
     * @param templateName 模板名称
     */
    public void sendTemplateThymeleaf(List<String> toUsers, List<String> ccUsers, String subject, Map<String, Object> data, String templateName) {
        if (sender == null || toUsers == null || subject == null) {
            log.error("MailUtils sendTemplateThymeleaf param error!");
            return;
        }
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        try {
            MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true);
            // 发送人
            messageHelper.setFrom(sender);
            // 接收人
            messageHelper.setTo(toUsers.toArray(new String[toUsers.size()]));
            // 抄送人
            if (ccUsers != null) {
                messageHelper.setCc(ccUsers.toArray(new String[ccUsers.size()]));
            }
            // 邮件标题
            messageHelper.setSubject(subject);

            //使用模板thymeleaf
            Context context = new Context();
            // 定义模板数据
            context.setVariables(data);
            //获取thymeleaf的html模板
            String emailContent = templateEngine.process(templateName, context);
            messageHelper.setText(emailContent, true);

            // 发送邮件
            javaMailSender.send(mimeMessage);
            log.info("thymeleaf模板邮件发送成功...");
        } catch (Exception e) {
            log.error("MailUtils sendTemplateThymeleaf error", e);
            throw new RuntimeException("邮件发送失败！");
        }
    }


}
